//
//  MNNetwork.swift
//  SwiftDemo
//
//  Created by jacknan on 2019/6/28.
//  Copyright © 2019 upbest. All rights reserved.
//

import UIKit
import Alamofire

let enable_MNNetworkLog = true
let default_timeoutInterval: TimeInterval = 15

var BaseUrl:String = "http://10.0.20.28:8770"
fileprivate let dateFormatter = DateFormatter.init()
fileprivate var date: String {
    let d = Date.init()
    dateFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss:SSS"
    return dateFormatter.string(from: d)
}

//打印日志
fileprivate func MNNetworkLog(_ messages: Any...) {
    if enable_MNNetworkLog {
        let message = messages.compactMap{ "\($0)" }.joined(separator: " ")
        print("\(date)\(message)")
    }
}

class MNNetwork {
    //MARK:- propertys
    static let shared = MNNetwork()
    var requestIndex: Int = 0                   //请求的位置 每次请求+1
    
    /// 默认添加的请求头
    var defaultHTTPHeaders = [String: String]()
    
    lazy var sessionManager:Session = {
        let configuration = URLSessionConfiguration.af.default
        configuration.timeoutIntervalForRequest = default_timeoutInterval
        let manager = Session(configuration: configuration)
        return manager
    }()
    
    func cancel() {
        sessionManager.session.invalidateAndCancel()
    }
    
    //MARK:- 原生写法
    
    open func request(
        _ url: URLConvertible,
        method: HTTPMethod = .get,
        parameters: Parameters? = nil,
        encoding: ParameterEncoding = URLEncoding.default,
        headers: HTTPHeaders? = nil)
        -> DataRequest
    {
        return sessionManager.request(url, method: method, parameters: parameters, encoding: encoding, headers: headers)
    }
    
    //MARK:- 封装请求方法
    func request(req:MNBaseReq, callBack: ((_ rsp: MNBaseRsp)->())?) {
        requestIndex += 1
        req.identifier = requestIndex
        //加入默认请求头
        defaultHTTPHeaders.forEach { (arg0) in
            let (key, value) = arg0
            req.httpHeaders[key] = value
        }
        
        MNNetworkLog("\(req.method == .get ? "GET":"POST")(\(req.identifier)):\(req.url.absoluteString)\(req.toJSONString() ?? "") headers:\(req.httpHeaders)")
         do {
            var request = try URLRequest.init(url: req.url, method: req.method, headers: HTTPHeaders.init(req.httpHeaders))
            request = try req.method == .get ? URLEncoding.default.encode(request, with: req.toJSON()):JSONEncoding.default.encode(request, with: req.toJSON())
            
            request.timeoutInterval = req.timeoutInterval ?? default_timeoutInterval
            sessionManager.request(request).responseJSON {[weak self] (dataResponse) in
                self?.responseAction(req: req, dataResponse: dataResponse, callBack: callBack)
            }
        }catch{
            self.responseAction(req: req, dataResponse: nil, callBack: callBack)
        }
    }
    
    /// 上传文件
    func upload(req: MNBaseReq, callBack: ((_ rsp: MNBaseRsp)->())?) {
        guard let datas = req.uploadFiles, datas.count > 0 else {
            assert(false, "uploadFiles is empty!")
            self.responseAction(req: req, dataResponse: nil, callBack: callBack)
            return
        }
        
        //加入默认请求头
        defaultHTTPHeaders.forEach { (arg0) in
            let (key, value) = arg0
            req.httpHeaders[key] = value
        }
        
        let formData = MultipartFormData(fileManager: .default)
        for i in 0..<datas.count {
            let item = datas[i]
            if let data = item.data {
                formData.append(data, withName: item.name, fileName: item.fileName, mimeType: item.type)
                MNNetworkLog("upload file :\(item.fileName) size:\(item.data?.count ?? 0)")
            }
        }
        
        do {
            var request = try URLRequest.init(url: req.url, method: req.method, headers: HTTPHeaders.init(req.httpHeaders))
            request = try URLEncoding.default.encode(request, with: req.toJSON())
            request.timeoutInterval = req.timeoutInterval ?? default_timeoutInterval
            sessionManager.upload(multipartFormData: formData, with: request, usingThreshold: MultipartFormData.encodingMemoryThreshold, interceptor: nil).responseJSON {[weak self] (dataResponse) in
                self?.responseAction(req: req, dataResponse: dataResponse, callBack: callBack)
            }
        }catch{
            assert(false, "creat request failed")
            self.responseAction(req: req, dataResponse: nil, callBack: callBack)
        }
    }

    /// 请求返回处理
    ///
    /// - Parameters:
    ///   - req: 请求模型
    ///   - dataResponse: 返回对象
    ///   - action: 回调
    func responseAction(req: MNBaseReq, dataResponse: DataResponse<Any, AFError>?, callBack: ((_ rsp: MNBaseRsp)->())?) {
        // 打印请求结果
        if let error = dataResponse?.error {
            MNNetworkLog("responseError:\(error)")
        }else{
            if let str = (dataResponse!.value as AnyObject).debugDescription.unicodeString {
                MNNetworkLog("responese(\(req.identifier)):" + str)
            }else{
                MNNetworkLog("responese is nil")
            }
        }
        
        // 解析请求结果
        var rsp = req.rspClass().deserialize(from: dataResponse?.value as? [String:Any]) as? MNBaseRsp
        if rsp == nil { rsp = req.rspClass().deserialize(from: ["code":"1"]) as? MNBaseRsp }
        rsp?.dataResponse = dataResponse
        rsp?.identifier = req.identifier
        callBack?(rsp!)
    }
}

fileprivate extension String {
    
    /// 控制台打印中文
    var unicodeString: String! {
        let tempStr1 = self.replacingOccurrences(of: "\\u", with: "\\U")
        let tempStr2 = tempStr1.replacingOccurrences(of: "\"", with: "\\\"")
        let tempStr3 = "\"".appending(tempStr2).appending("\"")
        let tempData = tempStr3.data(using: String.Encoding.utf8)
        var returnStr:String = ""
        do {
            returnStr = try PropertyListSerialization.propertyList(from: tempData!, options: [.mutableContainers], format: nil) as! String
        } catch {
            print(error)
        }
        return returnStr.replacingOccurrences(of: "\\r\\n", with: "\n")
    }
    
    /// 含有中文字符串的 url编码
    ///
    /// - Returns: 编码后的字符串（不含中文）
    func urlEncode()-> String {
        return self.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? self
    }
}

